package Hxw3DEngine.core.materials.shader.filters {
	
	import flash.utils.ByteArray;
	import Hxw3DEngine.core.Resource.geometry.ResourceGeometry;
	import Hxw3DEngine.core.materials.shader.utils.VcRegisterLabel;
	import Hxw3DEngine.core.materials.shader.utils.ShaderRegisterCache;
	import Hxw3DEngine.core.materials.shader.utils.ShaderRegisterElement;
	
	/**
	 * 四元数骨骼 
	 * @author Neil
	 * 
	 */	
	public class SkeletonFilterQuat extends SkeletonFilterBase {
		
		public function SkeletonFilterQuat() {
			super("SkeletonFilterQuat");
		}

		
		override public function getVertexCode(regCache : ShaderRegisterCache) : String {
			super.getVertexCode(regCache);
			// 56 * 2
			var bones : ShaderRegisterElement = regCache.getVc(MAX_QUAT_BONE * 2, boneLabel,"骨骼数据");
			var vc123 : ShaderRegisterElement = regCache.getVc(1, new VcRegisterLabel(Vector.<Number>([2 * 255, 1, 2, 3])),"vc123");
			var useNormal : Boolean = regCache.useNormal();
			
			var indexConst:uint = vc123.index;
			var indexOffset0:uint = bones.index;
			var indexOffset1:uint = indexOffset0 + 1;			
			
			var indexStream:ShaderRegisterElement = regCache.getVa(ResourceGeometry.SKIN_INDICES);
			var weightStream:ShaderRegisterElement = regCache.getVa(ResourceGeometry.SKIN_WEIGHTS);
			var indices:Array = [ indexStream.x, indexStream.y, indexStream.z, indexStream.w];
			var weights:Array = [ weightStream.xxxx, weightStream.yyyy, weightStream.zzzz, weightStream.wwww ];			
			
			var temp1 : ShaderRegisterElement = regCache.getVt("空闲VT1");
			var temp2 : ShaderRegisterElement = regCache.getVt("空闲VT2");
			var temp3 : ShaderRegisterElement = regCache.getVt("空闲VT3");
			var temp4 : ShaderRegisterElement = regCache.getVt("空闲VT4");
			var temp5 : ShaderRegisterElement = regCache.getVt("空闲VT5");
			
			var _jointsPerVertex:uint = 4;
			var _sourceRegisters:Vector.<ShaderRegisterElement> = new <ShaderRegisterElement>[regCache.getVa(ResourceGeometry.POSITION)];
			if (useNormal) {
				_sourceRegisters.push(regCache.getVa(ResourceGeometry.NORMAL));
			}
			var _targetRegisters:Vector.<ShaderRegisterElement> = new <ShaderRegisterElement>[regCache.op];
			var norm : ShaderRegisterElement = null;
			if (useNormal) {
				norm = regCache.getVt("空闲VT6");
				_sourceRegisters.push(norm);
			}
			var len:uint = _sourceRegisters.length;
			
			// blendDQ[0]权重累加到temp1中    blendDQ[1]权重累加到temp2中
			for (var j:uint = 0; j < _jointsPerVertex; ++j) {
				// add or mov to target. Need to write to a temp reg first, because an output can be a target
				
				mul(temp4.x,indices[j],"vc"+indexConst + ".x");
				
				if (j == 0) {
					mul(temp1.xyzw, weights[j],"vc[" + temp4 + ".x+" + indexOffset0 + "].xyzw");
					mul(temp2.xyzw,	weights[j],"vc["+ temp4 + ".x+" + indexOffset1 + "].xyzw");
				}
				else {
				
					mul(temp3.xyzw, weights[j], "vc[" + temp4 + ".x+" + indexOffset0 + "].xyzw");
					add(temp1.xyzw, temp1.xyzw, temp3.xyzw);
					mul(temp3.xyzw, weights[j], "vc[" + temp4 + ".x+" + indexOffset1 + "].xyzw");
					add(temp2.xyzw,temp2.xyzw,temp3.xyzw);
				}
			}

			// blendDQ[0] = blendDQ[0] * InvLength(blendDQ[0]) -> temp1
			// blendDQ[1] = blendDQ[1] * InvLength(blendDQ[0]) -> temp2
			
			dp4(temp3.x, temp1.xyzw, temp1.xyzw);
			rsq(temp4.x, temp3.xxxx);
			mul(temp1.xyzw, temp1.xyzw, temp4.xxxx);
			mul(temp2.xyzw,temp2.xyzw,temp4.xxxx);
			
			for (var i:uint = 0; i < len; ++i) {

				var src:String = _sourceRegisters[i].toString();

				// result -> temp3
				
				// tmp1 = cross(blendDQ[0].xyz, IN.position.xyz)
				crs(temp3.xyz, temp1.xyzz, src + "xyzz");
				
				// tmp0 = blendDQ[0].w*IN.position.xyz
				mul(temp4.xyz, temp1.wwww, src + "xyzz");
				
				// tmp2 = tmp1 + tmp0
				add(temp3.xyz, temp3.xyzz, temp4.xyzz);
				
				// tmp3 = cross(blendDQ[0].yzw, tmp2)
				crs(temp4.xyz, temp1.xyzz, temp3.xyzz);
				
				// tmp4 = 2.0*tmp3
				mul(temp4.xyz, "vc" + indexConst + ".zzzz", temp4.xyzz);
				
				// tmp5 = IN.position.xyz + tmp4
				add(temp3.xyz,src+"xyzz",temp4.xyzz);
				
				if(i == 0){
					// 位置需要做平移变化
					
					//	tmp6 = blendDQ[0].w*blendDQ[1].xyz
					mul(temp4.xyz, temp1.wwww, temp2.xyzz);
					
					//	tmp7 = blendDQ[1].w*blendDQ[0].xyz
					mul(temp5.xyz, temp2.wwww, temp1.xyzz);
					
					//  tmp9 = tmp6 - tmp7
					sub(temp4.xyz, temp4.xyzz, temp5.xyzz);
					
					//	tmp8 = cross(blendDQ[0].yzw, blendDQ[1].yzw)
					crs(temp5.xyz, temp1.xyzz, temp2.xyzz);
					
					//	tmp10 = tmp9 + tmp8
					add(temp4.xyz, temp5.xyzz, temp4.xyzz);
					
					//	tmp11 = 2.0*(tmp10)
					mul(temp4.xyz, "vc" + indexConst + ".zzzz", temp4.xyzz);
					
					//	position = tmp5 + tmp11
					add(temp5.xyz, temp3.xyzz, temp4.xyzz);
					
					mov(temp5.w, "vc" + indexConst + ".y");
					mov(_targetRegisters[i],temp5);
				
				
				}else{
					// 法线只需要四元数旋转，平移不用计算了。
					//code1 += "mov " + temp3 + ".w, " + "vc"+ indexConst + ".y\n" +
						//	"mov " + _targetRegisters[i] + ", " + temp3 + "\n";
					mov(temp3.w, "vc" + indexConst + ".y");
					mov(_targetRegisters[i],temp3);
				}
			}
			
			if (useNormal) {
				//code1 += 'm33 ' + nrm + '.xyz, ' + nrm + '.xyz, ' + regCache.vcWorld + ' \n';
				//code1 += 'nrm ' + regCache.getV(ResourceGeometry.NORMAL) + '.xyz, ' + nrm + '.xyz \n';
				m33(norm.xyz, norm.xyz, regCache.vcWorld);
				nrm(regCache.getV(ResourceGeometry.NORMAL).xyz,norm.xyz);
			}
			
			regCache.removeVt(temp1);
			regCache.removeVt(temp2);
			regCache.removeVt(temp3);
			regCache.removeVt(temp4);
			regCache.removeVt(temp5);
			
			if (useNormal) {
				regCache.removeVt(norm);
			}
			return code;
		}
		
	}
}
